'''
Created on Jan 15, 2018
Use iris's file for classification through SVM
@author: WangXin
'''

#!/usr/bin/python
# -*- coding:utf-8 -*-

import itertools
import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
from sklearn import svm
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.metrics import confusion_matrix

#计算混淆矩阵
def plot_confusion_matrix(cm, classes,
                          normalize=False,
                          title='Confusion matrix',
                          cmap=plt.cm.Blues):
    """
    This function prints and plots the confusion matrix.
    Normalization can be applied by setting `normalize=True`.
    """
    if normalize:
        cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]
        print("Normalized confusion matrix")
    else:
        print('Confusion matrix, without normalization')

    print(cm)

    plt.imshow(cm, interpolation='nearest', cmap=cmap)
    plt.title(title)
    plt.colorbar()
    tick_marks = np.arange(len(classes))
    plt.xticks(tick_marks, classes, rotation=45)
    plt.yticks(tick_marks, classes)

    fmt = '.2f' if normalize else 'd'
    thresh = cm.max() / 2.
    for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
        plt.text(j, i, format(cm[i, j], fmt),
                 horizontalalignment="center",
                 color="white" if cm[i, j] > thresh else "black")

    plt.tight_layout()
    plt.ylabel('True label')
    plt.xlabel('Predicted label')




if __name__ == "__main__":
    iris_feature = '花萼长度', '花萼宽度', '花瓣长度', '花瓣宽度'
    path = './iris.data'  # 数据文件路径
    data = pd.read_csv(path, header=None) #读取csv文件
    x, y = data[[0, 1]], pd.Categorical(data[4]).codes #编码，提取花萼长度，花萼宽度和类别
    class_names = ('setosa','versicolor','virginica')
    x_train, x_test, y_train, y_test = train_test_split(x, y, random_state=1, train_size=0.6)

    # 分类器-线性核linear
    #clf = svm.SVC(C=0.1, kernel='linear',decision_function_shape='ovr',probability=True)#训练集准确率0.8，测试集0.8

    # 分类器-poly核
    #clf = svm.SVC(C=0.1,kernel='poly',coef0=0,gamma=100,degree=1,decision_function_shape='ovo ',probability=True)#训练集准确率0.8，测试集0.7833

    # 分类器-rbf核
    #clf = svm.SVC(C=0.9, kernel='rbf', gamma=10, decision_function_shape='ovr',probability=True) #训练集准确率0.8666，测试集0.6833
    #clf = svm.SVC(C=5, kernel='rbf', gamma=2, decision_function_shape='ovo',probability=True)  # 训练集准确率0.8222，测试集0.8
    clf = svm.SVC(C=0.5, kernel='rbf', gamma=1, decision_function_shape='ovo', probability=True)  # 训练集准确率0.8222，测试集0.8166

    # 分类器-sigmoid核
    #clf = svm.SVC(C=100, kernel='sigmoid',coef0=0.2,gamma=0.2, decision_function_shape='ovo', probability=True)

    clf.fit(x_train, y_train.ravel())

    #用于混淆矩阵的计算
    #y_pred = clf.fit(x_train,y_train).predict(x_test)
    y_pred = clf.predict(x_test)

    # 准确率
    print(clf.score(x_train, y_train))  # 精度
    print('训练集准确率：', accuracy_score(y_train, clf.predict(x_train)))
    print(clf.score(x_test, y_test))
    print('测试集准确率：', accuracy_score(y_test, clf.predict(x_test)))

    # print(x_train[:5])

    # decision_function  各个类到超平面的距离
    print('decision_function:\n', clf.decision_function(x_train))
    print('\npredict_train:\n', clf.predict(x_train))
    #用模型预测值
    print('\nreal_test:\n',y_test)
    print('\npredict_test:\n',clf.predict(x_test))
    #分类器得分，返回概率值
    print('\n分类器得分：\n',clf.predict_proba(x_train))

    #返回支持向量
    print('\n各类支持向量：\n',clf.n_support_)#各类各有多少个支持向量
    print('\n各类支持向量在训练样本中的索引：\n',clf.support_)#各类支持向量在训练样本中的索引
    print('\n各类所有支持向量：\n',clf.support_vectors_)#各类所有支持向量

    # 画图
    x1_min, x2_min = x.min() #x1_min=4.3,x2_min=2
    x1_max, x2_max = x.max() #x1_max=7.9,x2_max =4.4   花萼长度x1,花萼宽度x2
    x1, x2 = np.mgrid[x1_min:x1_max:1000j, x2_min:x2_max:1000j]  # 生成网格采样点

    grid_test = np.stack((x1.flat, x2.flat), axis=1)  # 测试点
    grid_hat = clf.predict(grid_test)       # 预测分类值
    grid_hat = grid_hat.reshape(x1.shape)   # 使之与输入的形状相同
    mpl.rcParams[u'font.sans-serif'] = ['simhei']#改字体为黑体
    mpl.rcParams['axes.unicode_minus'] = False   #防止减号显示不正常

    cm_light = mpl.colors.ListedColormap(['#A0FFA0', '#FFA0A0', '#A0A0FF'])
    cm_dark = mpl.colors.ListedColormap(['g', 'r', 'b'])

    #画图fig1
    fig1 = plt.figure('figure1')
    ax = fig1.add_subplot(111)

    #plt.figure(facecolor='w')
    plt.pcolormesh(x1, x2, grid_hat, cmap=cm_light)
    ax.scatter(x[0], x[1], c=y, edgecolors='k', s=50, cmap=cm_dark)            # 样本
    ax.scatter(x_test[0], x_test[1], s=120, facecolors='none', zorder=10)      # 圈中测试集样本
    plt.xlabel(iris_feature[0], fontsize=13)
    plt.ylabel(iris_feature[1], fontsize=13)
    plt.xlim(x1_min, x1_max)
    plt.ylim(x2_min, x2_max)

    #画图各类支持向量
    circle=Circle((4.8,3),0.06,facecolor='none',edgecolor='k',linewidth=1,alpha=1)
    ax.add_patch(circle)

    plt.title(u'SVM二特征分类', fontsize=16) #鸢尾花
    plt.grid(b=True, ls=':')
    plt.tight_layout(pad=1.5)

    #plt.show()
    #画图fig2
    #评估性能指标-混淆矩阵
    #fig2 = plt.figure('figure2')

    #计算混淆矩阵
    cnf_matrix = confusion_matrix(y_test, y_pred)
    np.set_printoptions(precision=2)

    # Plot non-normalized confusion matrix
    plt.figure()    #figure2
    plot_confusion_matrix(cnf_matrix, classes=class_names,
                          title='Confusion matrix, without normalization')

    # Plot normalized confusion matrix
    plt.figure()    #figure3
    plot_confusion_matrix(cnf_matrix, classes=class_names, normalize=True,
                          title='Normalized confusion matrix')

    plt.show()
